package com.lanqiao.tree.threadedbinarytree;


public class ThreadedBinaryTreeDemo {
	public static void main(String[] args) {
		HeroNode root = new HeroNode(1, "宋江");
		HeroNode node2 = new HeroNode(3, "吴用");
		HeroNode node3 = new HeroNode(6, "卢俊义");
		HeroNode node4 = new HeroNode(8, "林冲");
		HeroNode node5 = new HeroNode(10, "关胜");
		HeroNode node6 = new HeroNode(14, "胜");
		
		root.setLeft(node2);
		root.setRight(node3);
		node2.setLeft(node4);
		node2.setRight(node5);
		node3.setLeft(node6);
		
		node2.setParent(root);
		node3.setParent(root);
		node4.setParent(node2);
		node5.setParent(node2);
		node6.setParent(node3);
		
		BinaryTree binaryTree = new BinaryTree();
		binaryTree.setRoot(root);
		//binaryTree.postOrder();
		binaryTree.threadedNodes1();
		binaryTree.postThreadList();
		
//		HeroNode resNode = node2.getRight();
//		System.out.println(resNode);
		
		//binaryTree.preOrder();
//		binaryTree.threadedNodes();//中序线索化
		

		//binaryTree.threadedList0();
//		binaryTree.threadedList();//中序线索化遍历
		
	}
}

//定义一棵二叉树
//定义ThreadedBinaryTree，实现线索化功能的二叉树
class BinaryTree {
	private HeroNode root;
	
	//为实现线索化，需要创建指向当前节点的前驱的指针
	//在递归进行线索化时，pre总是保留前一个结点
	//解决单向链表不能回退的问题
	private HeroNode pre = null;
	
	public void setRoot(HeroNode root) {
		this.root = root;
	}
	
	//前序遍历线索二叉树
	public void threadedList0() {
		HeroNode node = root;
		while (node != null) {
			System.out.println(node);
			while (node.getLeftType() == 0) {
				node = node.getLeft();
				System.out.println(node);
			}
			while (node.getRightType() == 1) {
				node = node.getRight();
				System.out.println(node);
			}
			node = node.getRight();
		}
	}
	
	
	//中序遍历线索二叉树
	public void threadedList() {
		HeroNode node = root;
		while (node != null) {
			//循环找到leftType==1，的结点
			//后面随着遍历而变化，因为当leftType==1，说明该节点是按照线索化
			//处理后的有效节点
			while (node.getLeftType() == 0) {
				node = node.getLeft();
			}
			//打印当前这个节点
			System.out.println(node);
			//如果当前节点的右指针指向的是后继节点，就一直输出
			while (node.getRightType() == 1) {
				//获取到当前节点的后继节点
				node = node.getRight();
				System.out.println(node);
			}
			//替换这个遍历的结点
			node = node.getRight();
		}
	}
	
	//后续遍历线索二叉树
    void postThreadList() {
        //1、找后序遍历方式开始的节点
        HeroNode node = root;
        while(node != null && node.getRightType() == 0) {
            node = node.getLeft();
        }

        HeroNode preNode = null;
        while(node != null) {
            //右节点是线索
            if(node.getRightType() == 1) {
                System.out.println(node);
                preNode = node;
                node = node.getRight();

            } else {
                //如果上个处理的节点是当前节点的右节点
                if(node.getRight() == preNode) {
                    System.out.println(node);
                    if(node == root) {
                        return;
                    }

                    preNode = node;
                    node = node.getParent();

                } else {    //如果从左节点的进入则找到有子树的最左节点
                    node = node.getRight();
                    while(node != null && node.getLeftType() == 0) {
                        node = node.getLeft();
                    }
                }
            }
        }
    }
	
	public void threadedNodes0() {
		threadedNodes0(root);
	}
	
	//前序线索化
	public void threadedNodes0(HeroNode node) {
		if (node == null) {
			return;
		}
		//线索化当前结点
		
		//处理当前节点的前驱结点
		if (node.getLeft() == null) {
			node.setLeft(pre);
			//修改前驱节点的指向类型
			node.setLeftType(1);
		}
		//处理当前结点的后继结点
		//使用pre，解决单项链表不能回退的问题
		if (pre != null && pre.getRight() == null) {
			//让前驱节点的右指针指向当前节点
			pre.setRight(node);
			//修改指向类型
			pre.setRightType(1);
		}
		pre = node;
		
		//线索化左子树
		if (node.getLeftType() == 0) {
			threadedNodes0(node.getLeft());
		}
		//线索化右子树
		if (node.getRightType() == 0) {
			threadedNodes0(node.getRight());
		}
	}
	
	
	
	public void threadedNodes() {
		threadedNodes(root);
	}
	
	//中序线索化
	public void threadedNodes(HeroNode node) {
		if (node == null) {
			return;
		}
		//先线索化左子树
		threadedNodes(node.getLeft());
		//线索化当前节点
		
		//处理当前节点的前驱结点
		if (node.getLeft() == null) {
			node.setLeft(pre);
			//修改指向类型为前驱
			node.setLeftType(1);
		}
		//处理当前节点的后继节点
		//pre就解决了单向链表不能回退的问题
		if (pre != null && pre.getRight() == null) {
			//让前驱节点的右指针指向当前节点
			pre.setRight(node);
			//修改指向类型
			pre.setRightType(1);
		}
		//每处理一个节点后，让当前结点是下一个节点的前驱结点
		pre = node;
		
		//线索化右子树
		threadedNodes(node.getRight());
	}
	
	public void threadedNodes1() {
		threadedNodes1(root);
	}
	
	
	//后序线索化
	public void threadedNodes1(HeroNode node) {
		if (node == null) {
			return;
		}
		//先线索化左子树
		threadedNodes1(node.getLeft());
		//线索化右子树
		threadedNodes1(node.getRight());
		//处理当前节点的前驱结点
		if (node.getLeft() == null) {
			node.setLeft(pre);
			//修改指向类型为前驱
			node.setLeftType(1);
		}
		//处理当前节点的后继节点
		//pre就解决了单向链表不能回退的问题
		if (pre != null && pre.getRight() == null) {
			//让前驱节点的右指针指向当前节点
			pre.setRight(node);
			//修改指向类型
			pre.setRightType(1);
		}
		//每处理一个节点后，让当前结点是下一个节点的前驱结点
		pre = node;
	}
	
	//删除结点
	public void delNode(int no) {
		if (root != null) {
			if (root.getNo() == no) {
				root = null;
			}else {
				root.delNode(no);
			}
		}else {
			System.out.println("空树！");
		}
	}
	
	//前序遍历
	public void preOrder() {
		if (this.root != null) {
			this.root.preOrder();
		}else {
			System.out.println("当前二叉树为空！");
		}
	}
	
	//中序
	public void infixOrder() {
		if (this.root != null) {
			this.root.infixOrder();
		}else {
			System.out.println("当前二叉树为空！");
		}
	}
	
	//后续
	public void postOrder() {
		if (this.root != null) {
			this.root.postOrder();
		}else {
			System.out.println("当前二叉树为空！");
		}
	}
	
	//前序遍历查找
	public HeroNode preOrderSearch(int no) {
		if (root != null) {
			return root.preOrderSearch(no);
		}else {
			return null;
		}
	}
	
	//中序
	public HeroNode infixOrderSearch(int no) {
		if (root != null) {
			return root.infixOrderSearch(no);
		}else {
			return null;
		}
	}
	
	//后续
	public HeroNode postOrderSearch(int no) {
		if (root != null) {
			return root.postOrderSearch(no);
		}else {
			return null;
		}
	}
}


//先创建HeroNode结点
class HeroNode {
	private int no;
	private String name;
	private HeroNode left;
	private HeroNode right;
	private HeroNode parent;//父节点，（为后序线索化使用）
	//说明
	//1. leftType == 0表明指向的是左子树，1指向前驱节点
	//2. rightType 同理
	private int leftType;
	private int rightType;
	
	
	public HeroNode getParent() {
		return parent;
	}

	public void setParent(HeroNode parent) {
		this.parent = parent;
	}

	public int getLeftType() {
		return leftType;
	}

	public void setLeftType(int leftType) {
		this.leftType = leftType;
	}

	public int getRightType() {
		return rightType;
	}

	public void setRightType(int rightType) {
		this.rightType = rightType;
	}

	public HeroNode(int no, String name) {
		this.no = no;
		this.name = name;
	}

	public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public HeroNode getLeft() {
		return left;
	}

	public void setLeft(HeroNode left) {
		this.left = left;
	}

	public HeroNode getRight() {
		return right;
	}

	public void setRight(HeroNode right) {
		this.right = right;
	}

	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + "]";
	}
	
	//递归删除结点
	//1. 如果删除的结点是叶子节点，则删除该节点
	//2. 如果删除的结点是非叶子节点，则删除该子树
	public void delNode(int no) {
		if (this.left != null && this.left.no == no) {
			this.left = null;
			return;
		}
		if (this.right != null && this.right.no == no) {
			this.right = null;
			return;
		}
		if (this.left != null) {
			this.left.delNode(no);
		}
		if (this.right != null) {
			this.right.delNode(no);
		}
	}
	
	//前序遍历
	public void preOrder() {
		System.out.println(this);//先输出父节点
		//递归左子树
		if (this.left != null) {
			this.left.preOrder();
		}
		//递归右子树
		if (this.right != null) {
			this.right.preOrder();
		}
	}
	
	//中序遍历
	public void infixOrder() {
		//递归左子树
		if (this.left != null) {
			this.left.infixOrder();
		}
		//输出父节点
		System.out.println(this);
		//递归右子树
		if (this.right != null) {
			this.right.infixOrder();
		}
		
	}
	
	//后续遍历
	public void postOrder() {
		//递归左子树
		if (this.left != null) {
			this.left.postOrder();
		}
		//递归右子树
		if (this.right != null) {
			this.right.postOrder();
		}
		//输出父节点
		System.out.println(this);
	}
	
	//前序遍历查找
	public HeroNode preOrderSearch(int no) {
		//比较当前结点是不是
		if (this.no  == no) {
			return this;
		}
		//判断当前结点的左子节点是否为空，不为空，就递归
		HeroNode resNode = null;
		if (this.left != null) {
			resNode = this.left.preOrderSearch(no);
		}
		//说明在左边找到了
		if (resNode != null) {
			return resNode;
		}
		//判断当前结点的右子节点是否为空，不为空，就递归
		if (this.right != null) {
			resNode = this.right.preOrderSearch(no);
		}
		return resNode;
	}
	
	//中序遍历查找
	public HeroNode infixOrderSearch(int no) {
		//当前结点的左子节点是否为空，不为空，递归查找
		HeroNode resNode = null;
		if (this.left != null) {
			resNode = this.left.infixOrderSearch(no);
		}
		if (resNode != null) {
			return resNode;
		}
		if (this.no == no) {
			return this;
		}
		//右递归
		if (this.right != null) {
			resNode = this.right.infixOrderSearch(no);
		}
		return resNode;
	}
	
	//后续查找
	public HeroNode postOrderSearch(int no) {
		HeroNode resNode = null;
		if (this.left != null) {
			resNode = this.left.postOrderSearch(no);
		}
		if (resNode != null) {
			return resNode;
		}
		if (this.right != null) {
			resNode = this.right.postOrderSearch(no);
		}
		if (resNode != null) {
			return resNode;
		}
		if (this.no == no) {
			return this;
		}
		return resNode;
	}
}